package com.dataextend.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.dataextend.mapper.cluster.UserGroupMapper;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.dataextend.dto.PropertyAndActDTO;
import com.dataextend.mapper.cluster.UserProfileMapper;
import com.dataextend.mapper.master.ClickhouseMapper;
import io.swagger.models.auth.In;
import lombok.extern.slf4j.Slf4j;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.search.Scroll;
import org.elasticsearch.action.search.*;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.Scroll;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 *   用户人群计算
 */
@Slf4j
@Service
public class UserGroupCalculateServiceV2 {
    @Autowired
    RestHighLevelClient restHighLevelClient;
    @Value("${usertag_all.usertag_all.index}")
    private String usertagIndex;
    @Value("${usertag_all.usertag_all.source_field}")
    private String usertagSourceField;
    @Value("${usertag_all.usertag_all.type}")
    private String type;
    @Autowired
    private UserProfileService userProfileService;
    @Autowired
    private UserGroupMapper userGroupMapper;
    @Autowired
    private ClickhouseMapper clickhouseMapper;

    private static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(2, 2,
            1000, TimeUnit.MILLISECONDS,
            new SynchronousQueue<Runnable>(),
            Executors.defaultThreadFactory(),
            new ThreadPoolExecutor.AbortPolicy());


    /**
     * 属性规则
     */
    private Integer propertyRules (PropertyAndActDTO.propertyRules propertyRules) {
        Pattern p = Pattern.compile(".*\\d+.*");
        String relationship = propertyRules.getRelationship();
        List<String> sqlArray = new ArrayList<>();
        for (PropertyAndActDTO.ruleDetails details : propertyRules.getRuleDetails()) {
            String key = details.getKey();
            String value = details.getValue();
            String condition = details.getCondition();
            Matcher m = p.matcher(value);  // 判断value值是否是数字比较大小
            String sqlInfo = "";
            if (m.matches()) {
                sqlInfo = "cast(" + key + " as Double) " + condition + " cast(" + value + " as Double)";
            } else {
                sqlInfo = key + " " + condition + " '" + value + "' ";
            }
            sqlArray.add(sqlInfo);
        }
        String sqlResult = "select count(*) from userprofile_info where " + String.join(" " + relationship + " ",sqlArray);
        log.info(">>>>属性规则SQL:" + sqlResult);
        Integer groupNum = clickhouseMapper.userGroupNumByAct(sqlResult);
        return groupNum;
    }



    /**
     * 行为规则
     */
    private Integer actRules(PropertyAndActDTO.actRules actRules) {
        Integer groupNum = 0;
        String clickhouseSql = "";
        if (actRules.getRelationship().equals("and")) {
            // TODO 行为规则之间是且关系
            int i=1;
            List<String> sqlArray = new ArrayList<>();
            for (PropertyAndActDTO.actDetails rule : actRules.getActDetails()) {
                String sqlDetail = "";
                String sqlDetail1 = "(select distinct_id,count(*) as num from userprofile_analysis_model ";
                String sqlDetail2 = "where clickevent" + rule.getActType() + "'" + rule.getEventCode() + "' and datadate>='" ;
                String sqlDetail3 = rule.getStartDate() + "' and datadate<='" + rule.getEndDate() + "' ";
                String sqlDetail4 = "group by distinct_id having count(*) >=" + rule.getNum() + ") t" + i;
                if (i>1) {
                    String sqlDetail5 = "  on t" + (i-1)+ ".distinct_id = t" + i + ".distinct_id";
                    sqlDetail = sqlDetail1 + sqlDetail2 + sqlDetail3 + sqlDetail4 + sqlDetail5;
                } else {
                    sqlDetail = sqlDetail1 + sqlDetail2 + sqlDetail3 + sqlDetail4;
                }
                sqlArray.add(sqlDetail);
                i+=1;
            }
            clickhouseSql = "select count(*) from " + String.join(" inner join ", sqlArray);
        } else {
            // TODO 行为规则之间是或关系
            List<String> sqlArray = new ArrayList<>();
            for (PropertyAndActDTO.actDetails rule : actRules.getActDetails()) {
                String sqlDetail1 = "select distinct_id,count(*) as num  from userprofile_analysis_model ";
                String sqlDetail2 = "where clickevent" + rule.getActType() + "'" + rule.getEventCode() + "' and datadate>='" ;
                String sqlDetail3 = rule.getStartDate() + "' and datadate<='" + rule.getEndDate() + "' ";
                String sqlDetail4 = "group by distinct_id having count(*) >=" + rule.getNum() ;
                String sqlDetail = sqlDetail1 + sqlDetail2 + sqlDetail3 + sqlDetail4;
                sqlArray.add(sqlDetail);
            }
            clickhouseSql = "select count(distinct t.distinct_id) from(" + String.join(" union all ", sqlArray) + " )  t ";
        }
        log.info(">>>>行为规则SQL:" + clickhouseSql);
        groupNum = clickhouseMapper.userGroupNumByAct(clickhouseSql);
        return groupNum;
    }


    /**
     * 属性规则 + 行为规则
     */
    private Integer allRules(PropertyAndActDTO userGroupRequest) {
        Integer groupNum=0;
        // TODO 查询SQL
        String clickhouseSQL = "";

        // TODO 属性SQL拼接
        String propertySQL = "";
        Pattern p = Pattern.compile(".*\\d+.*");
        String relationship = userGroupRequest.getPropertyRules().getRelationship();
        List<String> propertySqlArray = new ArrayList<>();
        for (PropertyAndActDTO.ruleDetails details : userGroupRequest.getPropertyRules().getRuleDetails()) {
            String key = details.getKey();
            String value = details.getValue();
            String condition = details.getCondition();
            Matcher m = p.matcher(value);  // 判断value值是否是数字比较大小
            String sqlInfo = "";
            if (m.matches()) {
                sqlInfo = "cast(" + key + " as Double) " + condition + " cast(" + value + " as Double)";
            } else {
                sqlInfo = key + " " + condition + " '" + value + "' ";
            }
            propertySqlArray.add(sqlInfo);
        }
        propertySQL = "select userid from userprofile_info where " + String.join(" " + relationship + " ",propertySqlArray);
        log.info(">>>>>属性SQL拼接:" + propertySQL);

        // TODO 行为SQL拼接
        String actSQL = "";
        if (userGroupRequest.getActRules().getRelationship().equals("and")) {
            //  行为规则之间是且关系
            int i=1;
            List<String> sqlArray = new ArrayList<>();
            for (PropertyAndActDTO.actDetails rule : userGroupRequest.getActRules().getActDetails()) {
                String sqlDetail = "";
                String sqlDetail1 = "(select distinct_id,count(*) as num from userprofile_analysis_model ";
                String sqlDetail2 = "where clickevent" + rule.getActType() + "'" + rule.getEventCode() + "' and datadate>='" ;
                String sqlDetail3 = rule.getStartDate() + "' and datadate<='" + rule.getEndDate() + "' ";
                String sqlDetail4 = "group by distinct_id having count(*) >=" + rule.getNum() + ") t" + i;
                if (i>1) {
                    String sqlDetail5 = "  on t" + (i-1)+ ".distinct_id = t" + i + ".distinct_id";
                    sqlDetail = sqlDetail1 + sqlDetail2 + sqlDetail3 + sqlDetail4 + sqlDetail5;
                } else {
                    sqlDetail = sqlDetail1 + sqlDetail2 + sqlDetail3 + sqlDetail4;
                }
                sqlArray.add(sqlDetail);
                i+=1;
            }
            actSQL = "select t1.distinct_id from " + String.join(" inner join ", sqlArray) + " group by t1.distinct_id";
        } else {
            //  行为规则之间是或关系
            List<String> sqlArray = new ArrayList<>();
            for (PropertyAndActDTO.actDetails rule : userGroupRequest.getActRules().getActDetails()) {
                String sqlDetail1 = "select distinct_id,count(*) as num  from userprofile_analysis_model ";
                String sqlDetail2 = "where clickevent" + rule.getActType() + "'" + rule.getEventCode() + "' and datadate>='" ;
                String sqlDetail3 = rule.getStartDate() + "' and datadate<='" + rule.getEndDate() + "' ";
                String sqlDetail4 = "group by distinct_id having count(*) >=" + rule.getNum() ;
                String sqlDetail = sqlDetail1 + sqlDetail2 + sqlDetail3 + sqlDetail4;
                sqlArray.add(sqlDetail);
            }
            actSQL = "select t.distinct_id from(" + String.join(" union all ", sqlArray) + " )  t group by t.distinct_id";
        }
        log.info(">>>>>行为SQL拼接:" + actSQL);

        clickhouseSQL = "select count(distinct a1.userid) from (" + propertySQL + " ) a1 inner join (" + actSQL + ") a2 on a1.userid=a2.distinct_id";
        log.info(">>>clickhouseSQL:" + clickhouseSQL);
        groupNum = clickhouseMapper.userGroupNumByAct(clickhouseSQL);
        return groupNum;
    }



    /**
     *  用户属性+用户行为 人数计算
     */
    public Integer propertyAndActCalculate(PropertyAndActDTO userGroupRequest) {
        Integer groupNum = 0;
        switch (userGroupRequest.getRuleType()) {
            // 用户属性
            case "property" :
                groupNum = propertyRules(userGroupRequest.getPropertyRules());
                break;
            // 用户行为
            case "act":
                groupNum = actRules(userGroupRequest.getActRules());
                break;
            // 用户属性+行为
            case "all":
                groupNum = allRules(userGroupRequest);
                break;
        }
        return groupNum;
    }


    /**
     *  用户属性+用户行为 条件保存
     */
    public void propertyAndActCalculateSave(PropertyAndActDTO userGroupRequest){
        SimpleDateFormat df2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String datadate = df2.format(new Date());

        switch (userGroupRequest.getRuleType()) {
            // 用户属性
            case "property" :
                Gson gson = new GsonBuilder().disableHtmlEscaping().create();
                String rulesInfo = gson.toJson(userGroupRequest.getPropertyRules());
                userGroupMapper.addUsergroupInfo(userGroupRequest.getGroupId(), userGroupRequest.getGroupName(), "super",
                        datadate, userGroupRequest.getComment(), "property",
                        rulesInfo, "",  userGroupRequest.getGroupNum());
                break;

            // 用户行为
            case "act":
                Gson gsonAct = new GsonBuilder().disableHtmlEscaping().create();
                String rulesInfoAct = gsonAct.toJson(userGroupRequest.getActRules());
                userGroupMapper.addUsergroupInfo(userGroupRequest.getGroupId(), userGroupRequest.getGroupName(), "super",
                        datadate, userGroupRequest.getComment(), "act",
                        "", rulesInfoAct,  userGroupRequest.getGroupNum());
                break;

            // 用户属性+行为
            case "all":
                Gson gsonAll = new GsonBuilder().disableHtmlEscaping().create();
                String propertyRulesInfo = gsonAll.toJson(userGroupRequest.getPropertyRules());
                String actRulesInfo = gsonAll.toJson(userGroupRequest.getActRules());
                userGroupMapper.addUsergroupInfo(userGroupRequest.getGroupId(), userGroupRequest.getGroupName(), "super", datadate,
                        userGroupRequest.getComment(), "all", propertyRulesInfo, actRulesInfo,  userGroupRequest.getGroupNum());
                break;
        }
    }

}
